﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using DVBViMon.Utils;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

namespace DVBViMon
{
    public partial class LoggingControl : UserControl
    {
        #region ctor

        /// <summary>
        /// Initializes a new instance of the <see cref="LoggingControl"/> class.
        /// </summary>
        public LoggingControl()
        {
            InitializeComponent();

            this.syncContext = SynchronizationContext.Current;

            // mapping tab index to presenter control
            this.index2Control = new Dictionary<int, BrightIdeasSoftware.TreeListView>() 
			{
				{ 0, this.treeListView1 },
				{ 1, this.treeListView2 },
				{ 2, this.treeListView3 },
				{ 3, this.treeListView4 }
			};

            // column "Level"
            this.colLevel0.ImageGetter =
            this.colLevel1.ImageGetter =
            this.colLevel2.ImageGetter =
            this.colLevel3.ImageGetter = (object row) =>
            {
                if (((LogEntry)row).Level == null)
                    return 3;

                return (int)((LogEntry)row).Level;
            };

            // column "Timestamp"
            this.colTimestamp0.AspectGetter =
            this.colTimestamp1.AspectGetter =
            this.colTimestamp2.AspectGetter =
            this.colTimestamp3.AspectGetter = (object row) =>
            {
                if (((LogEntry)row).Timestamp == null)
                    return null;

                return ((LogEntry)row).Timestamp.ToString();
            };

            // column "Message"
            this.colMessage0.AspectGetter =
            this.colMessage1.AspectGetter =
            this.colMessage2.AspectGetter =
            this.colMessage3.AspectGetter = (object row) =>
            {
                return ((LogEntry)row).Message;
            };

            // subtree availability check
            this.treeListView1.CanExpandGetter =
            this.treeListView2.CanExpandGetter =
            this.treeListView3.CanExpandGetter =
            this.treeListView4.CanExpandGetter = (object row) =>
            {
                return ((LogEntry)row).Details != null && ((LogEntry)row).Details.Any();
            };

            // subtree data
            this.treeListView1.ChildrenGetter =
            this.treeListView2.ChildrenGetter =
            this.treeListView3.ChildrenGetter =
            this.treeListView4.ChildrenGetter = (object row) =>
            {
                return ((LogEntry)row).Details;
            };
        }

        #endregion

        #region Implementation

        public void Update(LogEntry entryAdd, LogEntry entryRemove)
        {
            // enable cross-thread calling
            this.syncContext.Post(new SendOrPostCallback((s) =>
            {
                if (entryRemove != null)
                {
                    // remove entry from "Messages" tab
                    this.index2Control[0].RemoveObject(entryRemove);

                    // and from corresponding level tab
                    int pageIndex = (int)entryRemove.Level + 1;

                    this.index2Control[pageIndex].RemoveObject(entryRemove);

                    this.UpdatePageCounters(pageIndex);
                }

                // add new log entry
                if (entryAdd != null)
                {
                    // always add to "Messages" tab
                    this.index2Control[0].AddObject(entryAdd);

                    // and add to corresponding level tab
                    int pageIndex = (int)entryAdd.Level + 1;

                    this.index2Control[pageIndex].AddObject(entryAdd);

                    this.UpdatePageCounters(pageIndex);
                    this.EnsureLastEntryVisible();
                }

            }), null);
        }

        private void EnsureLastEntryVisible()
        {

            BrightIdeasSoftware.TreeListView selectedTab = this.index2Control[this.tabControl1.SelectedIndex];

            if (selectedTab.GetItemCount() > 0)
                selectedTab.EnsureVisible(selectedTab.GetItemCount() - 1);
        }

        private void UpdatePageCounters(int index)
        {
            this.tabControl1.TabPages[0].Text = string.Format("{0} {1}", this.index2Control[0].GetItemCount(),
                                                                         this.tabControl1.TabPages[0].Tag);

            this.tabControl1.TabPages[index].Text = string.Format("{0} {1}", this.index2Control[index].GetItemCount(),
                                                                             this.tabControl1.TabPages[index].Tag);
        }
        #endregion

        #region events

        private void LoggingControl_Load(object sender, EventArgs e)
        {
            //for (int i = 0; i < this.tabControl1.TabCount; ++i)
            //    this.tabControl1.TabPages[i].Text = string.Format("{0} {1}", this.index2Control[i].GetItemCount(),
            //                                                                 this.tabControl1.TabPages[i].Tag);
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {

            var treeListView = this.index2Control[this.tabControl1.SelectedIndex];
            e.Cancel = treeListView.GetItemCount() == 0;

            if (e.Cancel == false)
                this.copySelectionToClipboardToolStripMenuItem.Enabled = treeListView.SelectedIndices.Count > 0;
        }

        private void clearLogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var logger = EnterpriseLibraryContainer.Current.GetInstance<Logger<LogEntry>>();
            logger.Reset();

            // update GUI
            // clear all list entries
            foreach (var item in this.index2Control.Values)
                item.SetObjects(null);

            // restore page tab titles
            foreach (TabPage item in this.tabControl1.TabPages)
                item.Text = item.Tag.ToString();
        }


        private void copyAllToClipboardToolstripMenuItem_Click(object sender, EventArgs e)
        {
            var treeListView = this.index2Control[this.tabControl1.SelectedIndex];
            var list = treeListView.Objects.OfType<LogEntry>().ToList();
            treeListView.CopyObjectsToClipboard(list);
        }

        private void copySelectionToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var treeListView = this.index2Control[this.tabControl1.SelectedIndex];
            treeListView.CopySelectionToClipboard();
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            EnsureLastEntryVisible();
        }

        #endregion

        #region Fields

        /// <summary>
        /// Maps tab indices to presenting control
        /// </summary>
        Dictionary<int, BrightIdeasSoftware.TreeListView> index2Control;

        SynchronizationContext syncContext;

        #endregion

    }
}
